Skip to content

refactor: dedup estimateNeurons and the configured-repo-set assembly - #10179

Merged
JSONbored merged 2 commits into
mainfrom
fix/dedup-ai-usage-estimate
Jul 31, 2026
Merged

refactor: dedup estimateNeurons and the configured-repo-set assembly#10179
JSONbored merged 2 commits into
mainfrom
fix/dedup-ai-usage-estimate

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Closes #10169 · Refs #10170

Two duplication findings from the maintainability audit, bundled because they are the same class and both are bounded.

1. estimateNeurons — four copies, already drifted, under-reporting real spend

ai-review.ts exports the canonical version taking a calls multiplier. ai-chat-qa, ai-summaries and ai-intent-router each kept a private copy without it. extractAiText is duplicated across the same three, byte-identical.

This is not just tidiness. estimatedNeurons is both the pre-flight budget gate and the value recorded into ai_usage_events, which sumAiEstimatedNeuronsSince totals as the shared daily neuron budget. ai-chat-qa retries its provider call on an empty completion:

for (let attempt = 0; attempt < 2 && !rawText; attempt += 1) {

Two calls, one call's neurons recorded — hiding spend from the backstop whose job is to notice runaway spend, in the one direction that matters.

Fix. Both helpers move to a leaf module (ai-usage-estimate.ts) all callers import. Deliberately not imported from ai-review.ts: that file is 3.6k lines and three small services should not depend on the review engine to divide a number by four. The chat surface's import-isolation contract (#4595 req 10) still holds — the new module reaches no write path — and its test still passes.

The pre-flight gate keeps the single-call estimate, which is all that is knowable before the first attempt. The recorded figure is now computed after the loop from calls actually made, so the two stop pretending to be one number. calls floors at 1, so a miscount can never report zero spend for work that happened.

2. Configured-repo-set assembly — five byte-identical copies

Three inside processors.ts, one each in pr-reconciliation.ts and sweep-watchdog.ts. Every fleet-wide sweep needs "which repos are in scope" and each rebuilt it.

Only the assembly moves. What each caller does next — resolve settings, require a real installation, apply its own eligibility rule — genuinely differs and stays at the call site. Extracting further would push those differences into flag parameters, which is how a shared helper ends up worse than the duplication it replaced.

The merge semantics were load-bearing and never directly tested: the convergence list wins on name but carries over a local row's installationId. Losing that makes an installed repo look uninstalled, and every caller that requires an installation skips it — a fleet-wide sweep quietly doing nothing. Now covered, along with the case-insensitive de-duplication and the omitted-not-null installationId shape the call sites' spreads depend on.

processors.ts: 16,913 → 16,886 lines. Small; the point is four copies that can no longer drift.

Verification

  • Full suite 26,345 passed / 0 failed; typecheck, dead-exports, dead-source-files, import-specifiers clean.
  • 7 + 6 new tests.
  • Mutation-tested on the estimator:
mutation caught
drop the calls multiplier (the drift being fixed)
remove the floor, so 0 calls reports 0 spend

estimateNeurons existed four times and extractAiText three, byte-identical
copies that had already drifted: ai-review.ts exports a version taking a
`calls` multiplier, while ai-chat-qa, ai-summaries and ai-intent-router each
kept a private copy without it.

That is not just duplication. `estimatedNeurons` is BOTH the pre-flight budget
gate and the value recorded into ai_usage_events, which
sumAiEstimatedNeuronsSince adds up as the shared daily neuron budget. ai-chat-qa
retries its provider call on an empty completion, so a retry spent two calls and
reported one -- hiding usage from the backstop whose job is to notice runaway
usage, in the one direction that matters.

Both helpers move to a leaf module both sides import. Deliberately not imported
from ai-review.ts: that file is 3.6k lines, and three small services should not
depend on the review engine to divide a number by four. The chat surface's
import-isolation contract (#4595 req 10) still holds -- the new module reaches
no write path -- and its test still passes.

The pre-flight gate keeps the single-call estimate, which is all that is
knowable before the first attempt. The RECORDED figure is now computed after the
loop from the calls actually made, so the two no longer pretend to be the same
number. `calls` floors at 1, so a miscount can never report zero spend for work
that happened.

Found by the maintainability audit (#10170).

Closes #10169
…pies

Assembling "which repos does a fleet-wide pass consider" was duplicated five
times, byte-identical: three copies inside queue/processors.ts and one each in
review/pr-reconciliation.ts and review/sweep-watchdog.ts. Every fleet-wide sweep
needs the same answer and every one of them rebuilt it.

Only the ASSEMBLY moves. What each caller does next -- resolving settings,
requiring a real installation, applying its own eligibility rule -- genuinely
differs and stays at the call site. Extracting further would push those
differences into flag parameters, which is how a shared helper ends up worse
than the duplication it replaced.

The merge semantics were load-bearing and untested: the convergence list wins on
name, but carries over a local row's installationId when one exists. Losing that
would make an installed repo look uninstalled, and every caller that requires an
installation would skip it -- a fleet-wide sweep quietly doing nothing. Now
covered directly, including the case-insensitive de-duplication and the
omitted-not-null installationId shape the call sites' spreads depend on.

processors.ts drops from 16,913 to 16,886 lines. Small, but the point is the
four remaining copies that can no longer drift.

Refs #10170
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@JSONbored JSONbored self-assigned this Jul 31, 2026
@loopover-orb

loopover-orb Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Important

🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨

⏳ LoopOver is waiting…

LoopOver has seen this pull request and is waiting on CI checks to finish before reviewing it. This comment will update once the review runs.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed · 🟨 Waiting

@JSONbored
JSONbored merged commit 515de46 into main Jul 31, 2026
4 checks passed
@JSONbored
JSONbored deleted the fix/dedup-ai-usage-estimate branch July 31, 2026 11:23
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.34%. Comparing base (456a55c) to head (9e3fba4).
⚠️ Report is 6 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #10179      +/-   ##
==========================================
- Coverage   92.21%   91.34%   -0.88%     
==========================================
  Files         932      934       +2     
  Lines      114112   114072      -40     
  Branches    27565    27547      -18     
==========================================
- Hits       105228   104194    -1034     
- Misses       7583     8772    +1189     
+ Partials     1301     1106     -195     
Flag Coverage Δ
backend 94.12% <100.00%> (-1.56%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/queue/processors.ts 94.50% <100.00%> (-0.04%) ⬇️
src/review/configured-repo-set.ts 100.00% <100.00%> (ø)
src/review/pr-reconciliation.ts 100.00% <100.00%> (ø)
src/review/sweep-watchdog.ts 100.00% <100.00%> (ø)
src/services/ai-chat-qa.ts 98.61% <100.00%> (-0.11%) ⬇️
src/services/ai-intent-router.ts 100.00% <100.00%> (ø)
src/services/ai-summaries.ts 99.09% <100.00%> (-0.07%) ⬇️
src/services/ai-usage-estimate.ts 100.00% <100.00%> (ø)

... and 3 files with indirect coverage changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cost: estimateNeurons is duplicated 4x and the copies drop the calls multiplier, under-reporting AI spend

1 participant